//@author A0088498A
package logic;

import gui.IUserInterface;

import java.util.HashMap;

import common.AttributeType;
import common.Command;
import common.CommandType;

/**
 * Undo Command Handler <br/>
 * Retrieve a previous executable from History and undo it <br/>
 * 
 */
public class UndoCommandHandler extends CommandHandler {
	private final String NO_COMMAND_IN_HISTORY = "\nThere is no executable command in history\n";
	private final String SUCCESS_UNDONE_COMMAND = "\nCommand %s has successfully undone\n";
	private final String REVERT_NON_EXE_CMD_ERROR = "\nAttempt to revert a non-executable command\n";

	public UndoCommandHandler(IUserInterface ui, String originalCommand, HashMap<AttributeType, String> attList) {
		super(ui, originalCommand, attList);
	}

	/**
	 * Needs to be explicitly called for the command to be started <br/>
	 * No syntax checking required (as no compulsory fields required) <br/>
	 */
	public void start() {
		execute();
	}

	/**
	 * Execute the Undo command <br/>
	 * First will ask for the latest executable command from Storage <br/>
	 * Then revert it to make a compliment <br/>
	 * And execute the compliment to neglect the effect of the latest executable
	 * command<br/>
	 * Compliment commands are not saved into History <br/>
	 * 
	 */
	private void execute() {
		try {
			// Get latest executable command
			Command undoCmd = _ui.getHistory().undo();
			if (undoCmd != null) {

				// Revert
				Command complimentCmd = revertCommand(undoCmd);

				// Execute
				switch (complimentCmd.getType()) {
				case add:
					getStorage().createTask(complimentCmd.getTask());
					break;
				case delete:
					getStorage().deleteTask(complimentCmd.getTask().getTaskId());
					break;
				case update:
					getStorage().deleteTask(complimentCmd.getTask().getTaskId());
					getStorage().createTask(getStorage().getBeforeUpdate());
					getStorage().setBeforeUpdateNull();
					break;
				default:
					throw new IllegalArgumentException();
				}

				// Report back to console
				writeToConsole(SUCCESS_UNDONE_COMMAND, undoCmd.getCommandString());
			} else {
				throw new Exception(NO_COMMAND_IN_HISTORY);
			}
		} catch (Exception e) {
			writeToConsole(e.getMessage());
		}
	}

	/**
	 * Return a "compliment" command by revert it. <br/>
	 * Compliment command is a command that can cancel the effect of the
	 * original command when executed. <br/>
	 * 
	 * @param cmd
	 *            the original command
	 * @return compliment of the input command. Command Type can be null if it
	 *         cannot be reverted
	 * @throws IllegalArgumentException
	 *             when the commandType of the command is not recognised as an
	 *             executable command type
	 */
	private Command revertCommand(Command cmd) throws IllegalArgumentException {
		CommandType complimentType = revertTaskType(cmd.getType());

		Command complimentCommand = new Command("", complimentType, cmd.getTask());

		return complimentCommand;
	}

	/**
	 * Revert a CommandType <br/>
	 * 
	 * @param type
	 *            to be reverted
	 * @return the reverted type, null if the type cannot be reverted
	 * @throws IllegalArgumentException
	 *             when the cmdType is not an executable command type
	 */
	private CommandType revertTaskType(CommandType type) throws IllegalArgumentException {
		CommandType revertedType = null;

		switch (type) {
		case add:
			revertedType = CommandType.delete;
			break;
		case delete:
			revertedType = CommandType.add;
			break;
		case update:
			revertedType = CommandType.update;
			break;
		default:
			revertedType = null;
			throw new IllegalArgumentException(REVERT_NON_EXE_CMD_ERROR);
		}

		return revertedType;
	}
}
